using System;
using System.Collections.Generic;
using UnityEngine;

namespace CGF
{
    public class ColliderManager : ComponentBase, IAwake, IUpdate, IDestroy
    {
        //仅用于防内存泄露观察
        public int _targets, _bullets;

        /// <summary>
        /// 外部监听事件(返回子弹和目标的GameObject)
        /// </summary>
        public event Action<GameObject, GameObject> onHitEnter, onHitStay, onHitExit;

        private List<ColliderGroup> targets = new List<ColliderGroup>();

        //能攻击的所有目标对象（包括子弹，撞船，滚石，钻头，激光）
        private List<ColliderGroup> bullets = new List<ColliderGroup>();

        public void Awake() { }

        //碰撞开始时触发
        public void HitEnter(ColliderGroup bullet, ColliderGroup target)
        {
            onHitEnter?.Invoke(bullet.gameObject, target.gameObject);
        }

        //碰撞停留时每个物理帧都触发
        public void HitStay(ColliderGroup bullet, ColliderGroup target)
        {
            onHitStay?.Invoke(bullet.gameObject, target.gameObject);
        }

        //碰撞结束时触发
        public void HitExit(ColliderGroup bullet, ColliderGroup target)
        {
            onHitExit?.Invoke(bullet.gameObject, target.gameObject);
        }

        public void Update()
        {
            for (int i = 0; i < bullets.Count; i++)
            {
                ColliderGroup bullet = bullets[i];
                if (!bullet)
                {
                    bullets.RemoveAt(i);
                    _bullets--;
                    continue;
                }

                if (!bullet.isActive) continue;

                if (bullet.lockTarget && bullet.lockTarget.isActive)
                {
                    //如果子弹是锁定的，只处理锁定的目标
                    if (OneBulletCheckOneTarget(bullet, bullet.lockTarget))
                    {
                        bullet._OnHitListen(this, bullet.lockTarget);
                    }
                    continue;
                }

                //没有锁定目标，全场目标计算
                bool isHited = false;
                for (int j = 0; j < targets.Count; j++)
                {
                    ColliderGroup target = targets[j];
                    if (!target)
                    {
                        targets.RemoveAt(j);
                        _targets--;
                        continue;
                    }
                    isHited = OneBulletCheckOneTarget(bullet, target);
                    if (isHited)
                    {
                        bullet._OnHitListen(this, target);
                        break;
                    }
                }
                if (isHited) continue;
            }
            for (int i = 0; i < bullets.Count; i++)
            {
                ColliderGroup bullet = bullets[i];
                for (int j = 0; j < bullet.colliders.Length; j++)
                {
                    bullet.colliders[j].RefreshLastPos();
                }
            }

            //检测碰撞离开
            for (int i = 0; i < targets.Count; i++)
            {
                targets[i]._OnExitListen();
            }
            for (int i = 0; i < bullets.Count; i++)
            {
                bullets[i]._OnExitListen();
            }

            //Log($"_targets：{_targets}");
            //Log($"_bullets：{_bullets}");
        }

        //子弹支持LineColliderUI、CircleColliderUI、BoxColliderUI三种，目标仅支持CircleColliderUI
        private bool OneBulletCheckOneTarget(ColliderGroup bullet, ColliderGroup target)
        {
            if (bullet.colliders == null) return false;
            for (int i = 0; i < bullet.colliders.Length; i++)
            {
                ColliderBase b_collider = bullet.colliders[i];
                if (b_collider is ColliderLineUI)
                {
                    if (target.colliders == null) continue;
                    for (int j = 0; j < target.colliders.Length; j++)
                    {
                        if (LineCheckToCircle(b_collider as ColliderLineUI, target.colliders[j] as ColliderCircleUI))
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    if (target.colliders == null) continue;
                    for (int j = 0; j < target.colliders.Length; j++)
                    {
                        if (CircleCheckToCircle(b_collider as ColliderCircleUI, target.colliders[j] as ColliderCircleUI))
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        private bool LineCheckToCircle(ColliderLineUI bullet, ColliderCircleUI target)
        {
            Vector2 b_lastPos = bullet.lastPos;
            Vector2 b_currPos = bullet.rectTransform.anchoredPosition;
            Vector2 targetCenter = target.rectTransform.anchoredPosition;
            float distance = target.radius * target.scale + bullet.radius * bullet.scale;
            //线碰撞:线到圆心的距离 <（圆半径+子弹半径）
            if (PowerOfSegmentToPoint(b_lastPos, b_currPos, targetCenter) < distance * distance)
            {
                return true;
            }
            return false;
        }

        private bool CircleCheckToCircle(ColliderCircleUI bullet, ColliderCircleUI target)
        {
            Vector2 bulletCenter = bullet.rectTransform.anchoredPosition;
            Vector2 targetCenter = target.rectTransform.anchoredPosition;
            float distance = target.radius * target.scale + bullet.radius * bullet.scale;
            if (Vector2.Distance(bulletCenter, targetCenter) < distance)
            {
                return true;
            }
            return false;
        }

        // 线段和点的最短距离的平方
        private float PowerOfSegmentToPoint(Vector2 v1, Vector2 v2, Vector2 point)
        {
            float xDis = v2.x - v1.x;
            float yDis = v2.y - v1.y;
            float dx = point.x - v1.x;
            float dy = point.y - v1.y;
            float d = xDis * xDis + yDis * yDis;
            float t = xDis * dx + yDis * dy;//向量点积

            if (d > 0)
            {
                t /= d;
            }

            if (t < 0)
            {
                t = 0;
            }
            else if (t > 1)
            {
                t = 1;
            }
            dx = v1.x + t * xDis - point.x;
            dy = v1.y + t * yDis - point.y;
            return dx * dx + dy * dy;
        }

        //判断圆和矩形是否相交
        //box4Poits顺序：0:左上 1左下 2右下 3右上(左上开始逆时针)
        private bool IsBoxAndCircleOverlap(Vector2 boxMinPos, Vector2 boxMaxPos, Vector2[] box4Poits, Vector2 circleCenter, float circleRadius)
        {
            //判断圆再四点范围外
            if (circleCenter.x + circleRadius < boxMinPos.x ||
                circleCenter.x - circleRadius > boxMaxPos.x ||
                circleCenter.y + circleRadius < boxMinPos.y ||
                circleCenter.y - circleRadius > boxMaxPos.y)
            {
                return false;
            }

            //判断圆心在矩形内部
            Vector2 AB = box4Poits[3] - box4Poits[0];
            Vector2 AE = circleCenter - box4Poits[0];
            Vector2 CD = box4Poits[1] - box4Poits[2];
            Vector2 CE = circleCenter - box4Poits[2];
            Vector2 DA = box4Poits[0] - box4Poits[1];
            Vector2 DE = circleCenter - box4Poits[1];
            Vector2 BC = box4Poits[2] - box4Poits[3];
            Vector2 BE = circleCenter - box4Poits[3];

            if (Vector2.Dot(AB, AE) >= 0 && Vector2.Dot(CD, CE) >= 0 && Vector2.Dot(DA, DE) >= 0 && Vector2.Dot(BC, BE) >= 0)
            {
                return true;
            }

            //判断圆是否与四边相交
            if (PowerOfSegmentToPoint(box4Poits[0], box4Poits[1], circleCenter) < circleRadius * circleRadius)
            {
                return true;
            }
            if (PowerOfSegmentToPoint(box4Poits[1], box4Poits[2], circleCenter) < circleRadius * circleRadius)
            {
                return true;
            }
            if (PowerOfSegmentToPoint(box4Poits[2], box4Poits[3], circleCenter) < circleRadius * circleRadius)
            {
                return true;
            }
            if (PowerOfSegmentToPoint(box4Poits[3], box4Poits[0], circleCenter) < circleRadius * circleRadius)
            {
                return true;
            }
            return false;
        }

        //获取四个顶点的最小顶点和最大顶点
        private (Vector2 minPos, Vector2 maxPos) GetMinMaxPos(Vector2[] poses)
        {
            Vector2 minPos = new Vector2(poses[0].x, poses[0].y);
            Vector2 maxPos = new Vector2(poses[0].x, poses[0].y);
            for (int i = 0; i < poses.Length; i++)
            {
                if (poses[i].x < minPos.x) minPos.x = poses[i].x;
                if (poses[i].y < minPos.y) minPos.y = poses[i].y;
                if (poses[i].x > maxPos.x) maxPos.x = poses[i].x;
                if (poses[i].y > maxPos.y) maxPos.y = poses[i].y;
            }
            return (minPos, maxPos);
        }

        /// <summary>
        /// 如果一个对象内部有多个CircleCollider子物体，则此处添加的是该父级对象，而非把所有CircleCollider子物体都Add一次。
        /// </summary>
        public void AddTarget(GameObject gameObject)
        {
#if UNITY_EDITOR
            BoxCollider[] boxColliders = gameObject.GetComponentsInChildren<BoxCollider>();
            if (boxColliders.Length > 0)
            {
                Debug.LogError("目标对象不能使用 BoxCollider");
                return;
            }
#endif
            ColliderGroup colliderGroup = gameObject.GetComponent<ColliderGroup>();
            if (!colliderGroup) colliderGroup = gameObject.AddComponent<ColliderGroup>();
            if (!targets.Contains(colliderGroup))
            {
                targets.Add(colliderGroup);
                _targets++;
            }
        }

        /// <summary>
        /// 如果一个对象内部有多个CircleCollider子物体，则此处添加的是该父级对象，而非把所有CircleCollider子物体都Add一次。
        /// </summary>
        public void AddBullet(GameObject gameObject)
        {
            ColliderGroup colliderGroup = gameObject.GetComponent<ColliderGroup>();
            if (!colliderGroup) colliderGroup = gameObject.AddComponent<ColliderGroup>();
            if (!bullets.Contains(colliderGroup))
            {
                bullets.Add(colliderGroup);
                _bullets++;
            }
        }

        /// <summary>
        /// 移除子弹或目标对象
        /// </summary>
        public void Remove(GameObject gameObject)
        {
            ColliderGroup colliderGroup = gameObject.GetComponent<ColliderGroup>();
            if (!colliderGroup)
            {
                Debug.LogError("Remove对象错误");
                return;
            }

            //子弹更频繁，先判断子弹
            if (bullets.Contains(colliderGroup))
            {
                bullets.Remove(colliderGroup);
                _bullets--;
            }
            else if (targets.Contains(colliderGroup))
            {
                targets.Remove(colliderGroup);
                _targets--;
            }
        }

        /// <summary>
        /// 世界坐标的某点是否与ColliderGroup射线相交
        /// </summary>
        public ColliderGroup GetRayHitTarget(Vector2 touchWorldPos)
        {
            for (int i = 0; i < targets.Count; i++)
            {
                ColliderGroup target = targets[i];
                for (int j = 0; j < target.colliders.Length; j++)
                {
                    //已强制目标只能使用CircleCollider检测
                    ColliderCircleUI collider = target.colliders[j] as ColliderCircleUI;
                    Vector2 pos = collider.rectTransform.anchoredPosition;
                    float dis = Vector2.Distance(new Vector2(pos.x, pos.y), new Vector2(touchWorldPos.x, touchWorldPos.y));
                    if (dis <= collider.radius * collider.scale)
                    {
                        return target;
                    }
                }
            }
            return null;
        }

        public void Clear()
        {
            targets.Clear();
            bullets.Clear();
        }

        public void OnDestroy()
        {
            Clear();
        }

        /// <summary>
        /// 外部 Monobehaviour 调用。画出Debug线条
        /// </summary>
        public void OnDrawGizmos()
        {
            if (Application.isPlaying)
            {
                for (int i = 0; i < targets.Count; i++)
                {
                    targets[i].DrawGizmos();
                }
                for (int i = 0; i < bullets.Count; i++)
                {
                    bullets[i].DrawGizmos();
                }
            }
        }
    }
}